package org.ms.nerver.governor.fault.proxy;

import java.lang.reflect.Method;

import org.ms.nerver.governor.fault.Fault;
import org.ms.nerver.governor.proxy.JDKAbstractProxyFactory;
import org.ms.nerver.governor.retry.Retry;
import org.zbus.kit.log.Logger;

public class FaultProxyFactory extends JDKAbstractProxyFactory {

	private Logger logger=Logger.getLogger(FaultProxyFactory.class);
	
	public FaultProxyFactory(Object obj) {
		super(obj);
	}

	public void doBefore(Object proxy, Method method, Object[] args) {

	}
	
	/**
	 * 调度执行
	 */
	public Object doInvoke(Method method, Object proxy, Object[] args,Object...others) throws Throwable {
		Object result=null;
		
		Method implMethod=proxy.getClass().getMethod(method.getName(), method.getParameterTypes());
		if(implMethod!=null){
			Fault fault=implMethod.getAnnotation(Fault.class);
			Retry retry=implMethod.getAnnotation(Retry.class);
			
			if(fault!=null){//开启容错机制
				//周期性重试
				int retryTimes=1;
				if(retry!=null){
					retryTimes=retry.retryTimes();
				}
				if(retryTimes<1){
					throw new Throwable("'retryTimes' must be greater than 0.");
				}
				//备忘录模式
				int retryTimes_bak=retryTimes;
				
				while (retryTimes-->0) {
					try {
						return method.invoke(proxy, args);
					} catch (Throwable e) {
						logger.debug("调度重试第"+(retryTimes_bak-retryTimes)+"次");
						if(retryTimes==0){//失败完毕
							if(fault.fallbackMethod()==null||"".equals(fault.fallbackMethod())){//校验,抛出异常
								throw new Throwable("Invoke ["+method+"] was not found.");
							}
						}
					}
				}
				
				Method failbackImplMethod=proxy.getClass().getMethod(fault.fallbackMethod(), method.getParameterTypes());
				if(failbackImplMethod!=null){
					//周期性容错
					int fallbackRetryTimes=1;
					if(retry!=null){
						fallbackRetryTimes=retry.fallbackRetryTimes();
					}
					if(fallbackRetryTimes<1){
						throw new Throwable("'fallbackRetryTimes' must be greater than 0.");
					}
					//备忘录模式
					int fallbackRetryTimes_bak=fallbackRetryTimes;
					
					while (fallbackRetryTimes-->0) {
						try {
							return failbackImplMethod.invoke(proxy, args);
						} catch (Throwable e) {
							logger.debug("容错重试第"+(fallbackRetryTimes_bak-fallbackRetryTimes)+"次");
							if(fallbackRetryTimes==0){//抛出异常
								throw new Throwable("Failback Invoke ["+method+"] was failure.");
							}
						}
					}
				}else{
					throw new Throwable("Failback method ["+failbackImplMethod+"] was not found.");
				}
			}else{//未开启容错,则直接调度
				return super.doInvoke(implMethod, proxy, args,others);
			}
		}else{
			throw new Throwable("Invoke ["+method+"] was not found.");
		}
		return result;
	}

	public void doAfter(Object proxy, Method method, Object[] args, Object result) {

	}

	

}
